JavaScript์ WeakRef์ FinalizationRegistry๋ฅผ ํ์ฉํ์ฌ ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ธ ์ต์ ๋ฒ ํจํด์ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์ฌ์ธต์ ์ผ๋ก ์์๋ด ๋๋ค. ๋๊ท๋ชจ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํ๋ ๊ธฐ์ ์ ๋ฐฐ์ฐ์ธ์.
JavaScript WeakRef ์ต์ ๋ฒ ํจํด: ๋ฉ๋ชจ๋ฆฌ ์ธ์ ์ด๋ฒคํธ ์์คํ ๊ตฌ์ถํ๊ธฐ
ํ๋ ์น ๊ฐ๋ฐ์ ์ธ๊ณ์์ ๋จ์ผ ํ์ด์ง ์ ํ๋ฆฌ์ผ์ด์ (SPA)์ ๋์ ์ด๊ณ ๋ฐ์์ฑ์ด ๋ฐ์ด๋ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ง๋๋ ํ์ค์ด ๋์์ต๋๋ค. ์ด๋ฌํ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ข ์ข ์ฅ๊ธฐ๊ฐ ์คํ๋๋ฉฐ, ๋ณต์กํ ์ํ๋ฅผ ๊ด๋ฆฌํ๊ณ ์๋ง์ ์ฌ์ฉ์ ์ํธ์์ฉ์ ์ฒ๋ฆฌํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ด๋ฌํ ์ฅ์๋ช ์๋ ์จ๊ฒจ์ง ๋น์ฉ์ด ๋ฐ๋ฆ ๋๋ค: ๋ฐ๋ก ๋ฉ๋ชจ๋ฆฌ ๋์์ ์ํ ์ฆ๊ฐ์ ๋๋ค. ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ ์ด์ ํ์ํ์ง ์์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ณ์ ๋ถ๋ค๊ณ ์๋ ๋ฉ๋ชจ๋ฆฌ ๋์๋ ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ์ฑ๋ฅ์ ์ ํ์์ผ ๋๋ ค์ง, ๋ธ๋ผ์ฐ์ ์ถฉ๋, ๊ทธ๋ฆฌ๊ณ ์ข์ง ์์ ์ฌ์ฉ์ ๊ฒฝํ์ผ๋ก ์ด์ด์ง ์ ์์ต๋๋ค. ์ด๋ฌํ ๋์์ ๊ฐ์ฅ ํํ ์์ธ ์ค ํ๋๋ ๊ธฐ๋ณธ์ ์ธ ๋์์ธ ํจํด์ธ ์ต์ ๋ฒ ํจํด์ ์์ต๋๋ค.
์ต์ ๋ฒ ํจํด์ ์ด๋ฒคํธ ๊ธฐ๋ฐ ์ํคํ ์ฒ์ ์ด์์ผ๋ก, ๊ฐ์ฒด(์ต์ ๋ฒ)๊ฐ ์ค์ ๊ฐ์ฒด(์ฃผ์ฒด)๋ฅผ ๊ตฌ๋ ํ๊ณ ์ ๋ฐ์ดํธ๋ฅผ ๋ฐ์ ์ ์๊ฒ ํด์ค๋๋ค. ์ด๋ ์ฐ์ํ๊ณ ๊ฐ๋จํ๋ฉฐ ๋งค์ฐ ์ ์ฉํฉ๋๋ค. ๊ทธ๋ฌ๋ ๊ณ ์ ์ ์ธ ๊ตฌํ ๋ฐฉ์์๋ ์น๋ช ์ ์ธ ๊ฒฐํจ์ด ์์ต๋๋ค: ์ฃผ์ฒด๊ฐ ์ต์ ๋ฒ์ ๋ํ ๊ฐํ ์ฐธ์กฐ(strong reference)๋ฅผ ์ ์งํ๋ค๋ ๊ฒ์ ๋๋ค. ๋ง์ฝ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค๋ฅธ ๋ถ๋ถ์์ ๋ ์ด์ ์ต์ ๋ฒ๊ฐ ํ์ ์๊ฒ ๋์์ง๋ง ๊ฐ๋ฐ์๊ฐ ์ฃผ์ฒด๋ก๋ถํฐ ๋ช ์์ ์ผ๋ก ๊ตฌ๋ ์ ์ทจ์ํ๋ ๊ฒ์ ์๋๋ค๋ฉด, ๊ทธ ์ต์ ๋ฒ๋ ์ ๋ ๊ฐ๋น์ง ์ปฌ๋ ์ ๋์ง ์์ ๊ฒ์ ๋๋ค. ๊ทธ๊ฒ์ ๋ฉ๋ชจ๋ฆฌ์ ๊ฐํ ์ ํ๋ฆฌ์ผ์ด์ ์ฑ๋ฅ์ ๊ดด๋กญํ๋ ์ ๋ น์ผ๋ก ๋จ๊ฒ ๋ฉ๋๋ค.
๋ฐ๋ก ์ด ์ง์ ์์ ECMAScript 2021(ES12) ๊ธฐ๋ฅ์ ๊ฐ์ถ ํ๋ JavaScript๊ฐ ๊ฐ๋ ฅํ ํด๊ฒฐ์ฑ ์ ์ ๊ณตํฉ๋๋ค. WeakRef์ FinalizationRegistry๋ฅผ ํ์ฉํ์ฌ, ์ฐ๋ฆฌ๋ ์ด๋ฌํ ํํ ๋์๋ฅผ ๋ฐฉ์งํ๊ณ ์ค์ค๋ก ์ ๋ฆฌํ๋ ๋ฉ๋ชจ๋ฆฌ ์ธ์ ์ต์ ๋ฒ ํจํด์ ๊ตฌ์ถํ ์ ์์ต๋๋ค. ์ด ๊ธ์ ์ด ๊ณ ๊ธ ๊ธฐ์ ์ ๋ํ ์ฌ์ธต ๋ถ์์ ๋๋ค. ์ฐ๋ฆฌ๋ ๋ฌธ์ ๋ฅผ ํ๊ตฌํ๊ณ , ๋๊ตฌ๋ฅผ ์ดํดํ๋ฉฐ, ์ฒ์๋ถํฐ ๊ฒฌ๊ณ ํ ๊ตฌํ์ ๋ง๋ค์ด๋ณด๊ณ , ์ด ๊ฐ๋ ฅํ ํจํด์ด ์ฌ๋ฌ๋ถ์ ๊ธ๋ก๋ฒ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ธ์ ์ด๋์ ์ ์ฉ๋์ด์ผ ํ๋์ง ๋ ผ์ํ ๊ฒ์ ๋๋ค.
ํต์ฌ ๋ฌธ์ ์ดํดํ๊ธฐ: ํด๋์ ์ต์ ๋ฒ ํจํด๊ณผ ๋ฉ๋ชจ๋ฆฌ ์ ์
ํด๊ฒฐ์ฑ ์ ๊ฐ์น๋ฅผ ์ ๋๋ก ์๊ธฐ ์ ์, ์ฐ๋ฆฌ๋ ๋จผ์ ๋ฌธ์ ๋ฅผ ์์ ํ ํ์ ํด์ผ ํฉ๋๋ค. ๋ฐํ-๊ตฌ๋ (Publisher-Subscriber) ํจํด์ผ๋ก๋ ์๋ ค์ง ์ต์ ๋ฒ ํจํด์ ์ปดํฌ๋ํธ ๊ฐ์ ๊ฒฐํฉ์ ๋ฎ์ถ๊ธฐ ์ํด ์ค๊ณ๋์์ต๋๋ค. ์ฃผ์ฒด(Subject ๋๋ Publisher)๋ ์ต์ ๋ฒ(Observer ๋๋ Subscriber)๋ผ๊ณ ๋ถ๋ฆฌ๋ ์ข ์ ๊ฐ์ฒด๋ค์ ๋ชฉ๋ก์ ์ ์งํฉ๋๋ค. ์ฃผ์ฒด์ ์ํ๊ฐ ๋ณ๊ฒฝ๋๋ฉด, ์ฃผ์ฒด๋ ์๋์ผ๋ก ๋ชจ๋ ์ต์ ๋ฒ์๊ฒ ์๋ฆผ์ ๋ณด๋ด๋๋ฐ, ๋ณดํต update()์ ๊ฐ์ ํน์ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๋ฐฉ์์ผ๋ก ์ด๋ฃจ์ด์ง๋๋ค.
JavaScript๋ก ๊ตฌํ๋ ๊ฐ๋จํ ํด๋์ ์์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๊ฐ๋จํ Subject ๊ตฌํ
๋ค์์ ๊ธฐ๋ณธ์ ์ธ Subject ํด๋์ค์ ๋๋ค. ์ต์ ๋ฒ๋ฅผ ๊ตฌ๋ , ๊ตฌ๋ ์ทจ์ํ๊ณ ์๋ฆผ์ ๋ณด๋ด๋ ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
class ClassicSubject {
constructor() {
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
console.log(`${observer.name}๊ฐ ๊ตฌ๋ ํ์ต๋๋ค.`);
}
unsubscribe(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
console.log(`${observer.name}๊ฐ ๊ตฌ๋ ์ ์ทจ์ํ์ต๋๋ค.`);
}
notify(data) {
console.log('์ต์ ๋ฒ์๊ฒ ์๋ฆผ์ ๋ณด๋ ๋๋ค...');
this.observers.forEach(observer => observer.update(data));
}
}
๊ทธ๋ฆฌ๊ณ Subject๋ฅผ ๊ตฌ๋ ํ ์ ์๋ ๊ฐ๋จํ Observer ํด๋์ค์ ๋๋ค.
class Observer {
constructor(name) {
this.name = name;
}
update(data) {
console.log(`${this.name}๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ต๋๋ค: ${data}`);
}
}
์จ๊ฒจ์ง ์ํ: ์ฌ๋ผ์ง์ง ์๋ ์ฐธ์กฐ
์ด ๊ตฌํ์ ์ฐ๋ฆฌ๊ฐ ์ต์ ๋ฒ์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๋ถ์ง๋ฐํ ๊ด๋ฆฌํ๋ ํ ์๋ฒฝํ๊ฒ ์๋ํฉ๋๋ค. ๋ฌธ์ ๋ ๊ทธ๋ ์ง ์์ ๋ ๋ฐ์ํฉ๋๋ค. ๋๊ท๋ชจ ์ ํ๋ฆฌ์ผ์ด์ ์์ ํํ ๋ณผ ์ ์๋ ์๋๋ฆฌ์ค๋ฅผ ์๊ฐํด ๋ด ์๋ค: ์ค๋ ์ง์๋๋ ์ ์ญ ๋ฐ์ดํฐ ์ ์ฅ์(Subject)์ ๊ทธ ๋ฐ์ดํฐ์ ์ผ๋ถ๋ฅผ ํ์ํ๋ ์์ UI ์ปดํฌ๋ํธ(Observer)๊ฐ ์์ต๋๋ค.
์ด ์๋๋ฆฌ์ค๋ฅผ ์๋ฎฌ๋ ์ด์ ํด ๋ณด๊ฒ ์ต๋๋ค:
const dataStore = new ClassicSubject();
function manageUIComponent() {
let chartComponent = new Observer('ChartComponent');
dataStore.subscribe(chartComponent);
// ์ปดํฌ๋ํธ๊ฐ ์์ ์ ์ญํ ์ ์ํํฉ๋๋ค...
// ์ด์ ์ฌ์ฉ์๊ฐ ๋ค๋ฅธ ๊ณณ์ผ๋ก ์ด๋ํ์ฌ ์ปดํฌ๋ํธ๊ฐ ๋ ์ด์ ํ์ํ์ง ์์ต๋๋ค.
// ๊ฐ๋ฐ์๊ฐ ์ ๋ฆฌ ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ์์ ์ ์์ต๋๋ค:
// dataStore.unsubscribe(chartComponent);
chartComponent = null; // ์ปดํฌ๋ํธ์ ๋ํ ์ฐธ์กฐ๋ฅผ ํด์ ํฉ๋๋ค.
}
manageUIComponent();
// ์ ํ๋ฆฌ์ผ์ด์ ์๋ช ์ฃผ๊ธฐ์ ํ๋ฐ๋ถ...
dataStore.notify('์๋ก์ด ๋ฐ์ดํฐ๊ฐ ์์ต๋๋ค!');
`manageUIComponent` ํจ์์์ ์ฐ๋ฆฌ๋ `chartComponent`๋ฅผ ์์ฑํ๊ณ `dataStore`์ ๊ตฌ๋ ์ํต๋๋ค. ๋์ค์ ์ฐ๋ฆฌ๋ `chartComponent`๋ฅผ `null`๋ก ์ค์ ํ์ฌ ๋ ์ด์ ์ฌ์ฉํ์ง ์์์ ์๋ฆฝ๋๋ค. ์ฐ๋ฆฌ๋ JavaScript ๊ฐ๋น์ง ์ปฌ๋ ํฐ(GC)๊ฐ ์ด ๊ฐ์ฒด์ ๋ํ ์ฐธ์กฐ๊ฐ ๋ ์ด์ ์๋ค๊ณ ํ๋จํ๊ณ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ์ํ ๊ฒ์ผ๋ก ๊ธฐ๋ํฉ๋๋ค.
ํ์ง๋ง ๋ ๋ค๋ฅธ ์ฐธ์กฐ๊ฐ ์์ต๋๋ค! `dataStore.observers` ๋ฐฐ์ด์ ์ฌ์ ํ `chartComponent` ๊ฐ์ฒด์ ๋ํ ์ง์ ์ ์ด๊ณ ๊ฐํ ์ฐธ์กฐ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ด ํ๋์ ๋จ์์๋ ์ฐธ์กฐ ๋๋ฌธ์ ๊ฐ๋น์ง ์ปฌ๋ ํฐ๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ์ํ ์ ์์ต๋๋ค. `chartComponent` ๊ฐ์ฒด์ ๊ทธ๊ฒ์ด ๋ณด์ ํ ๋ชจ๋ ๋ฆฌ์์ค๋ `dataStore`์ ์ ์ฒด ์๋ช ์ฃผ๊ธฐ ๋์ ๋ฉ๋ชจ๋ฆฌ์ ๋จ์์๊ฒ ๋ฉ๋๋ค. ๋ง์ฝ ์ฌ์ฉ์๊ฐ ๋ชจ๋ฌ ์ฐฝ์ ์ด๊ณ ๋ซ์ ๋๋ง๋ค ์ด๋ฐ ์ผ์ด ๋ฐ๋ณต๋๋ค๋ฉด, ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ๋ฌดํ์ ์ฆ๊ฐํ ๊ฒ์ ๋๋ค. ์ด๊ฒ์ด ๋ฐ๋ก ๊ณ ์ ์ ์ธ ๋ฉ๋ชจ๋ฆฌ ๋์์ ๋๋ค.
์๋ก์ด ํฌ๋ง: WeakRef์ FinalizationRegistry ์๊ฐ
ECMAScript 2021์ ์ด๋ฌํ ์ข ๋ฅ์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ๋ฌธ์ ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด ํน๋ณํ ์ค๊ณ๋ ๋ ๊ฐ์ง ์๋ก์ด ๊ธฐ๋ฅ์ธ `WeakRef`์ `FinalizationRegistry`๋ฅผ ๋์ ํ์ต๋๋ค. ์ด๋ค์ ๊ณ ๊ธ ๋๊ตฌ์ด๋ฏ๋ก ์ ์คํ๊ฒ ์ฌ์ฉํด์ผ ํ์ง๋ง, ์ฐ๋ฆฌ์ ์ต์ ๋ฒ ํจํด ๋ฌธ์ ์๋ ์๋ฒฝํ ํด๊ฒฐ์ฑ ์ ๋๋ค.
WeakRef๋ ๋ฌด์์ธ๊ฐ?
A `WeakRef` ๊ฐ์ฒด๋ ๋ค๋ฅธ ๊ฐ์ฒด(ํ๊ฒ)์ ๋ํ ์ฝํ ์ฐธ์กฐ(weak reference)๋ฅผ ๊ฐ์ง๋๋ค. ์ฝํ ์ฐธ์กฐ์ ์ผ๋ฐ์ ์ธ (๊ฐํ) ์ฐธ์กฐ์ ํต์ฌ์ ์ธ ์ฐจ์ด์ ์ ์ด๊ฒ์ ๋๋ค: ์ฝํ ์ฐธ์กฐ๋ ํ๊ฒ ๊ฐ์ฒด๊ฐ ๊ฐ๋น์ง ์ปฌ๋ ์ ๋๋ ๊ฒ์ ๋ง์ง ์์ต๋๋ค.
๋ง์ฝ ํ ๊ฐ์ฒด์ ๋ํ ์ฐธ์กฐ๊ฐ ์ฝํ ์ฐธ์กฐ๋ค๋ฟ์ด๋ผ๋ฉด, JavaScript ์์ง์ ํด๋น ๊ฐ์ฒด๋ฅผ ํ๊ดดํ๊ณ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ์ํ ์ ์์ต๋๋ค. ์ด๊ฒ์ด ๋ฐ๋ก ์ฐ๋ฆฌ๊ฐ ์ต์ ๋ฒ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐ ํ์ํ ๊ฒ์ ๋๋ค.
`WeakRef`๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด, ์์ฑ์์ ํ๊ฒ ๊ฐ์ฒด๋ฅผ ์ ๋ฌํ์ฌ ์ธ์คํด์ค๋ฅผ ๋ง๋ญ๋๋ค. ๋์ค์ ํ๊ฒ ๊ฐ์ฒด์ ์ ๊ทผํ๋ ค๋ฉด `deref()` ๋ฉ์๋๋ฅผ ์ฌ์ฉํฉ๋๋ค.
let targetObject = { id: 42 };
const weakRefToObject = new WeakRef(targetObject);
// ๊ฐ์ฒด์ ์ ๊ทผํ๋ ค๋ฉด:
const retrievedObject = weakRefToObject.deref();
if (retrievedObject) {
console.log(`๊ฐ์ฒด๊ฐ ์์ง ์ด์์์ต๋๋ค: ${retrievedObject.id}`); // ์ถ๋ ฅ: Object is still alive: 42
} else {
console.log('๊ฐ์ฒด๊ฐ ๊ฐ๋น์ง ์ปฌ๋ ์ ๋์์ต๋๋ค.');
}
์ค์ํ ์ ์ `deref()`๊ฐ `undefined`๋ฅผ ๋ฐํํ ์ ์๋ค๋ ๊ฒ์ ๋๋ค. ์ด๋ `targetObject`์ ๋ํ ๊ฐํ ์ฐธ์กฐ๊ฐ ๋ ์ด์ ์กด์ฌํ์ง ์์ ๊ฐ๋น์ง ์ปฌ๋ ์ ๋์์ ๋ ๋ฐ์ํฉ๋๋ค. ์ด ๋์์ด ๋ฐ๋ก ์ฐ๋ฆฌ์ ๋ฉ๋ชจ๋ฆฌ ์ธ์ ์ต์ ๋ฒ ํจํด์ ๊ธฐ์ด์ ๋๋ค.
FinalizationRegistry๋ ๋ฌด์์ธ๊ฐ?
`WeakRef`๋ ๊ฐ์ฒด๊ฐ ์์ง๋๋๋ก ํ์ฉํ์ง๋ง, ๊ทธ๊ฒ์ด ์ธ์ ์์ง๋์๋์ง ๊น๋ํ๊ฒ ์ ์ ์๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ์ง๋ ์์ต๋๋ค. ์ฃผ๊ธฐ์ ์ผ๋ก `deref()`๋ฅผ ํ์ธํ๊ณ `undefined` ๊ฒฐ๊ณผ๋ฅผ ์ต์ ๋ฒ ๋ชฉ๋ก์์ ์ ๊ฑฐํ ์๋ ์์ง๋ง, ์ด๋ ๋นํจ์จ์ ์ ๋๋ค. ๋ฐ๋ก ์ด ์ง์ ์์ `FinalizationRegistry`๊ฐ ๋ฑ์ฅํฉ๋๋ค.
A `FinalizationRegistry`๋ ๋ฑ๋ก๋ ๊ฐ์ฒด๊ฐ ๊ฐ๋น์ง ์ปฌ๋ ์ ๋ ํ์ ํธ์ถ๋ ์ฝ๋ฐฑ ํจ์๋ฅผ ๋ฑ๋กํ ์ ์๊ฒ ํด์ค๋๋ค. ์ด๊ฒ์ ์ฌํ ์ ๋ฆฌ๋ฅผ ์ํ ๋ฉ์ปค๋์ฆ์ ๋๋ค.
์๋ ๋ฐฉ์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ ๋ฆฌ ์ฝ๋ฐฑ๊ณผ ํจ๊ป ๋ ์ง์คํธ๋ฆฌ๋ฅผ ์์ฑํฉ๋๋ค.
- `register()`๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ฒด๋ฅผ ๋ ์ง์คํธ๋ฆฌ์ ๋ฑ๋กํฉ๋๋ค. ๊ฐ์ฒด๊ฐ ์์ง๋ ๋ ์ฝ๋ฐฑ์ ์ ๋ฌ๋ ๋ฐ์ดํฐ ์กฐ๊ฐ์ธ `heldValue`๋ ์ ๊ณตํ ์ ์์ต๋๋ค. ์ด `heldValue`๋ ๊ฐ์ฒด ์์ฒด์ ๋ํ ์ง์ ์ ์ธ ์ฐธ์กฐ์ฌ์๋ ์ ๋ฉ๋๋ค. ๊ทธ๋ ๊ฒ ํ๋ฉด ๋ชฉ์ ์ ์ด๊ธ๋๊ธฐ ๋๋ฌธ์ ๋๋ค!
// 1. ์ ๋ฆฌ ์ฝ๋ฐฑ๊ณผ ํจ๊ป ๋ ์ง์คํธ๋ฆฌ๋ฅผ ์์ฑํฉ๋๋ค
const registry = new FinalizationRegistry(heldValue => {
console.log(`๊ฐ์ฒด๊ฐ ๊ฐ๋น์ง ์ปฌ๋ ์ ๋์์ต๋๋ค. ์ ๋ฆฌ ํ ํฐ: ${heldValue}`);
});
(function() {
let objectToTrack = { name: 'Temporary Data' };
let cleanupToken = 'temp-data-123';
// 2. ๊ฐ์ฒด๋ฅผ ๋ฑ๋กํ๊ณ ์ ๋ฆฌ๋ฅผ ์ํ ํ ํฐ์ ์ ๊ณตํฉ๋๋ค
registry.register(objectToTrack, cleanupToken);
// objectToTrack๊ฐ ์ฌ๊ธฐ์ ์ค์ฝํ๋ฅผ ๋ฒ์ด๋ฉ๋๋ค
})();
// ๋ฏธ๋์ ์ด๋ ์์ ์ GC๊ฐ ์คํ๋ ํ, ์ฝ์์ ๋ค์๊ณผ ๊ฐ์ด ๊ธฐ๋ก๋ฉ๋๋ค:
// "An object has been garbage collected. Cleanup token: temp-data-123"
์ค์ํ ์ฃผ์์ฌํญ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก
๊ตฌํ์ ๋ค์ด๊ฐ๊ธฐ ์ ์, ์ด ๋๊ตฌ๋ค์ ๋ณธ์ง์ ์ดํดํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๊ฐ๋น์ง ์ปฌ๋ ํฐ์ ๋์์ ๊ตฌํ์ ๋ฐ๋ผ ํฌ๊ฒ ๋ฌ๋ผ์ง๋ฉฐ ๋น๊ฒฐ์ ์ ์ ๋๋ค. ์ด๋ ๋ค์์ ์๋ฏธํฉ๋๋ค:
- ๊ฐ์ฒด๊ฐ ์ธ์ ์์ง๋ ์ง ์์ธกํ ์ ์์ต๋๋ค. ๋๋ฌ ๋ถ๊ฐ๋ฅํด์ง ํ ๋ช ์ด, ๋ช ๋ถ, ๋๋ ๊ทธ ์ด์์ด ๊ฑธ๋ฆด ์ ์์ต๋๋ค.
- `FinalizationRegistry` ์ฝ๋ฐฑ์ด ์๊ธฐ์ ์ ํ๊ฑฐ๋ ์์ธก ๊ฐ๋ฅํ ๋ฐฉ์์ผ๋ก ์คํ๋ ๊ฒ์ด๋ผ๊ณ ์์กดํ ์ ์์ต๋๋ค. ์ด๋ค์ ์ค์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ก์ง์ด ์๋ ์ ๋ฆฌ๋ฅผ ์ํ ๊ฒ์ ๋๋ค.
- `WeakRef`์ `FinalizationRegistry`์ ๋จ์ฉ์ ์ฝ๋๋ฅผ ์ดํดํ๊ธฐ ์ด๋ ต๊ฒ ๋ง๋ค ์ ์์ต๋๋ค. ๊ฐ์ฒด ์๋ช ์ฃผ๊ธฐ๊ฐ ๋ช ํํ๊ณ ๊ด๋ฆฌ ๊ฐ๋ฅํ๋ค๋ฉด ํญ์ ๋ช ์์ ์ธ `unsubscribe` ํธ์ถ๊ณผ ๊ฐ์ ๋ ๊ฐ๋จํ ํด๊ฒฐ์ฑ ์ ์ ํธํ์ธ์.
์ด ๊ธฐ๋ฅ๋ค์ ํ ๊ฐ์ฒด(์ต์ ๋ฒ)์ ์๋ช ์ฃผ๊ธฐ๊ฐ ๋ค๋ฅธ ๊ฐ์ฒด(์ฃผ์ฒด)์ ์ง์ ์ผ๋ก ๋ ๋ฆฝ์ ์ด๊ณ ์๋ ค์ง์ง ์์ ์ํฉ์ ๊ฐ์ฅ ์ ํฉํฉ๋๋ค.
`WeakRefObserver` ํจํด ๊ตฌ์ถํ๊ธฐ: ๋จ๊ณ๋ณ ๊ตฌํ
์ด์ `WeakRef`์ `FinalizationRegistry`๋ฅผ ๊ฒฐํฉํ์ฌ ๋ฉ๋ชจ๋ฆฌ ์์ ํ `WeakRefSubject` ํด๋์ค๋ฅผ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
1๋จ๊ณ: `WeakRefSubject` ํด๋์ค ๊ตฌ์กฐ
์๋ก์ด ํด๋์ค๋ ์ต์ ๋ฒ์ ๋ํ ์ง์ ์ ์ธ ์ฐธ์กฐ ๋์ `WeakRef`๋ฅผ ์ ์ฅํ ๊ฒ์ ๋๋ค. ๋ํ ์ต์ ๋ฒ ๋ชฉ๋ก์ ์๋ ์ ๋ฆฌ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด `FinalizationRegistry`๋ฅผ ๊ฐ์ง ๊ฒ์ ๋๋ค.
class WeakRefSubject {
constructor() {
this.observers = new Set(); // ์ฌ์ด ์ ๊ฑฐ๋ฅผ ์ํด Set ์ฌ์ฉ
// ํ์ด๋๋ผ์ด์ ์ฝ๋ฐฑ. ๋ฑ๋ก ์ ์ ๊ณตํ held value๋ฅผ ๋ฐ์ต๋๋ค.
// ์ฐ๋ฆฌ์ ๊ฒฝ์ฐ, held value๋ WeakRef ์ธ์คํด์ค ์์ฒด๊ฐ ๋ ๊ฒ์ ๋๋ค.
this.cleanupRegistry = new FinalizationRegistry(weakRefObserver => {
console.log('ํ์ด๋๋ผ์ด์ : ์ต์ ๋ฒ๊ฐ ๊ฐ๋น์ง ์ปฌ๋ ์ ๋์์ต๋๋ค. ์ ๋ฆฌ ์ค...');
this.observers.delete(weakRefObserver);
});
}
}
์ฐ๋ฆฌ๋ ์ต์ ๋ฒ ๋ชฉ๋ก์ `Array` ๋์ `Set`์ ์ฌ์ฉํฉ๋๋ค. `Set`์์ ํญ๋ชฉ์ ์ญ์ ํ๋ ๊ฒ์ด `Array`๋ฅผ ํํฐ๋งํ๋ ๊ฒ๋ณด๋ค ํจ์ฌ ํจ์จ์ ์ด๊ธฐ ๋๋ฌธ์ ๋๋ค(ํ๊ท ์๊ฐ ๋ณต์ก๋ O(1) vs O(n)). ์ด๋ ์ฐ๋ฆฌ์ ์ ๋ฆฌ ๋ก์ง์ ์ ์ฉํ ๊ฒ์ ๋๋ค.
2๋จ๊ณ: `subscribe` ๋ฉ์๋
`subscribe` ๋ฉ์๋๋ ๋ง๋ฒ์ด ์์๋๋ ๊ณณ์ ๋๋ค. ์ต์ ๋ฒ๊ฐ ๊ตฌ๋ ํ ๋, ์ฐ๋ฆฌ๋ ๋ค์์ ์ํํฉ๋๋ค:
- ์ต์ ๋ฒ๋ฅผ ๊ฐ๋ฆฌํค๋ `WeakRef`๋ฅผ ์์ฑํฉ๋๋ค.
- ์ด `WeakRef`๋ฅผ ์ฐ๋ฆฌ์ `observers` set์ ์ถ๊ฐํฉ๋๋ค.
- ์๋ก ์์ฑ๋ `WeakRef`๋ฅผ `heldValue`๋ก ์ฌ์ฉํ์ฌ ์๋ ์ต์ ๋ฒ ๊ฐ์ฒด๋ฅผ `FinalizationRegistry`์ ๋ฑ๋กํฉ๋๋ค.
// WeakRefSubject ํด๋์ค ๋ด๋ถ...
subscribe(observer) {
// ์ด ์ฐธ์กฐ๋ฅผ ๊ฐ์ง ์ต์ ๋ฒ๊ฐ ์ด๋ฏธ ์กด์ฌํ๋์ง ํ์ธ
for (const ref of this.observers) {
if (ref.deref() === observer) {
console.warn('์ด๋ฏธ ๊ตฌ๋ ๋ ์ต์ ๋ฒ์ ๋๋ค.');
return;
}
}
const weakRefObserver = new WeakRef(observer);
this.observers.add(weakRefObserver);
// ์๋ ์ต์ ๋ฒ ๊ฐ์ฒด๋ฅผ ๋ฑ๋กํฉ๋๋ค. ์ด ๊ฐ์ฒด๊ฐ ์์ง๋๋ฉด,
// ํ์ด๋๋ผ์ด์ ๋ `weakRefObserver`๋ฅผ ์ธ์๋ก ๋ฐ์ ํธ์ถ๋ฉ๋๋ค.
this.cleanupRegistry.register(observer, weakRefObserver);
console.log('์ต์ ๋ฒ๊ฐ ๊ตฌ๋ ํ์ต๋๋ค.');
}
์ด ์ค์ ์ ์๋ฆฌํ ๋ฃจํ๋ฅผ ๋ง๋ญ๋๋ค: ์ฃผ์ฒด๋ ์ต์ ๋ฒ์ ๋ํ ์ฝํ ์ฐธ์กฐ๋ฅผ ๊ฐ์ง๋๋ค. ๋ ์ง์คํธ๋ฆฌ๋ (๋ด๋ถ์ ์ผ๋ก) ์ต์ ๋ฒ๊ฐ ๊ฐ๋น์ง ์ปฌ๋ ์ ๋ ๋๊น์ง ๊ฐํ ์ฐธ์กฐ๋ฅผ ๊ฐ์ง๋๋ค. ์์ง๋๋ฉด, ๋ ์ง์คํธ๋ฆฌ์ ์ฝ๋ฐฑ์ด ์ฝํ ์ฐธ์กฐ ์ธ์คํด์ค์ ํจ๊ป ํธ๋ฆฌ๊ฑฐ๋๋ฉฐ, ์ฐ๋ฆฌ๋ ์ด๋ฅผ ์ฌ์ฉํ์ฌ `observers` set์ ์ ๋ฆฌํ ์ ์์ต๋๋ค.
3๋จ๊ณ: `unsubscribe` ๋ฉ์๋
์๋ ์ ๋ฆฌ๊ฐ ์๋๋ผ๋, ๊ฒฐ์ ๋ก ์ ์ ๊ฑฐ๊ฐ ํ์ํ ๊ฒฝ์ฐ๋ฅผ ์ํด ์๋ `unsubscribe` ๋ฉ์๋๋ฅผ ์ ๊ณตํด์ผ ํฉ๋๋ค. ์ด ๋ฉ์๋๋ ๊ฐ `WeakRef`๋ฅผ ์ญ์ฐธ์กฐํ๊ณ ์ฐ๋ฆฌ๊ฐ ์ ๊ฑฐํ๋ ค๋ ์ต์ ๋ฒ์ ๋น๊ตํ์ฌ set์์ ์ฌ๋ฐ๋ฅธ `WeakRef`๋ฅผ ์ฐพ์์ผ ํฉ๋๋ค.
// WeakRefSubject ํด๋์ค ๋ด๋ถ...
unsubscribe(observer) {
let refToRemove = null;
for (const weakRef of this.observers) {
if (weakRef.deref() === observer) {
refToRemove = weakRef;
break;
}
}
if (refToRemove) {
this.observers.delete(refToRemove);
// ์ค์: ํ์ด๋๋ผ์ด์ ์์๋ ๋ฑ๋ก์ ํด์ ํด์ผ ํฉ๋๋ค.
// ๋์ค์ ์ฝ๋ฐฑ์ด ๋ถํ์ํ๊ฒ ์คํ๋๋ ๊ฒ์ ๋ฐฉ์งํ๊ธฐ ์ํจ์ ๋๋ค.
this.cleanupRegistry.unregister(observer);
console.log('์ต์ ๋ฒ๊ฐ ์๋์ผ๋ก ๊ตฌ๋ ์ ์ทจ์ํ์ต๋๋ค.');
}
}
4๋จ๊ณ: `notify` ๋ฉ์๋
`notify` ๋ฉ์๋๋ `WeakRef` set์ ์ํํฉ๋๋ค. ๊ฐ `WeakRef`์ ๋ํด `deref()`๋ฅผ ์๋ํ์ฌ ์ค์ ์ต์ ๋ฒ ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์ต๋๋ค. `deref()`๊ฐ ์ฑ๊ณตํ๋ฉด ์ต์ ๋ฒ๊ฐ ์์ง ์ด์์๋ค๋ ์๋ฏธ์ด๋ฏ๋ก `update` ๋ฉ์๋๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค. `undefined`๋ฅผ ๋ฐํํ๋ฉด ์ต์ ๋ฒ๊ฐ ์์ง๋ ๊ฒ์ด๋ฏ๋ก ๊ทธ๋ฅ ๋ฌด์ํ๋ฉด ๋ฉ๋๋ค. `FinalizationRegistry`๊ฐ ๊ฒฐ๊ตญ set์์ ํด๋น `WeakRef`๋ฅผ ์ ๊ฑฐํ ๊ฒ์ ๋๋ค.
// WeakRefSubject ํด๋์ค ๋ด๋ถ...
notify(data) {
console.log('์ต์ ๋ฒ์๊ฒ ์๋ฆผ์ ๋ณด๋ ๋๋ค...');
for (const weakRefObserver of this.observers) {
const observer = weakRefObserver.deref();
if (observer) {
// ์ต์ ๋ฒ๊ฐ ์์ง ์ด์์์ต๋๋ค
observer.update(data);
} else {
// ์ต์ ๋ฒ๊ฐ ๊ฐ๋น์ง ์ปฌ๋ ์ ๋์์ต๋๋ค.
// FinalizationRegistry๊ฐ ์ด weakRef๋ฅผ set์์ ์ ๊ฑฐํ๋ ๊ฒ์ ์ฒ๋ฆฌํ ๊ฒ์ ๋๋ค.
console.log('์๋ฆผ ์ค ์ฃฝ์ ์ต์ ๋ฒ ์ฐธ์กฐ๋ฅผ ๋ฐ๊ฒฌํ์ต๋๋ค.');
}
}
}
๋ชจ๋ ํฉ์น๊ธฐ: ์ค์ฉ์ ์ธ ์์
UI ์ปดํฌ๋ํธ ์๋๋ฆฌ์ค๋ก ๋์๊ฐ๋, ์ด๋ฒ์๋ ์๋ก์ด `WeakRefSubject`๋ฅผ ์ฌ์ฉํด ๋ด ์๋ค. ๋จ์ํ๋ฅผ ์ํด ์ด์ ๊ณผ ๋์ผํ `Observer` ํด๋์ค๋ฅผ ์ฌ์ฉํ๊ฒ ์ต๋๋ค.
// ๋์ผํ ๊ฐ๋จํ Observer ํด๋์ค
class Observer {
constructor(name) {
this.name = name;
}
update(data) {
console.log(`${this.name}๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ต๋๋ค: ${data}`);
}
}
์ด์ ์ ์ญ ๋ฐ์ดํฐ ์๋น์ค๋ฅผ ๋ง๋ค๊ณ ์์ UI ์์ ฏ์ ์๋ฎฌ๋ ์ด์ ํด ๋ณด๊ฒ ์ต๋๋ค.
const globalDataService = new WeakRefSubject();
function createAndDestroyWidget() {
console.log('--- ์ ์์ ฏ ์์ฑ ๋ฐ ๊ตฌ๋ ---');
let chartWidget = new Observer('RealTimeChartWidget');
globalDataService.subscribe(chartWidget);
// ์์ ฏ์ด ํ์ฑํ๋์์ผ๋ฉฐ ์๋ฆผ์ ๋ฐ๊ฒ ๋ฉ๋๋ค
globalDataService.notify({ price: 100 });
console.log('--- ์์ ฏ ํ๊ดด (์ฐธ์กฐ ํด์ ) ---');
// ์์ ฏ ์ฌ์ฉ์ด ๋๋ฌ์ต๋๋ค. ์ฐธ์กฐ๋ฅผ null๋ก ์ค์ ํฉ๋๋ค.
// unsubscribe()๋ฅผ ํธ์ถํ ํ์๊ฐ ์์ต๋๋ค.
chartWidget = null;
}
createAndDestroyWidget();
console.log('--- ์์ ฏ ํ๊ดด ํ, ๊ฐ๋น์ง ์ปฌ๋ ์ ์ ---');
globalDataService.notify({ price: 105 });
`createAndDestroyWidget()`๋ฅผ ์คํํ ํ, `chartWidget` ๊ฐ์ฒด๋ ์ด์ `globalDataService` ๋ด๋ถ์ `WeakRef`์ ์ํด์๋ง ์ฐธ์กฐ๋ฉ๋๋ค. ์ด๊ฒ์ ์ฝํ ์ฐธ์กฐ์ด๋ฏ๋ก, ๊ฐ์ฒด๋ ์ด์ ๊ฐ๋น์ง ์ปฌ๋ ์ ๋์์ด ๋ฉ๋๋ค.
๊ฐ๋น์ง ์ปฌ๋ ํฐ๊ฐ ๊ฒฐ๊ตญ ์คํ๋๋ฉด(์ธ์ ์ผ์ง ์์ธกํ ์ ์์), ๋ ๊ฐ์ง ์ผ์ด ์ผ์ด๋ฉ๋๋ค:
- `chartWidget` ๊ฐ์ฒด๊ฐ ๋ฉ๋ชจ๋ฆฌ์์ ์ ๊ฑฐ๋ฉ๋๋ค.
- ์ฐ๋ฆฌ์ `FinalizationRegistry` ์ฝ๋ฐฑ์ด ํธ๋ฆฌ๊ฑฐ๋์ด, ์ด์ ๋ ์ฃฝ์ `WeakRef`๋ฅผ `globalDataService.observers` set์์ ์ ๊ฑฐํฉ๋๋ค.
๊ฐ๋น์ง ์ปฌ๋ ํฐ๊ฐ ์คํ๋ ํ `notify`๋ฅผ ๋ค์ ํธ์ถํ๋ฉด, `deref()` ํธ์ถ์ `undefined`๋ฅผ ๋ฐํํ๊ณ , ์ฃฝ์ ์ต์ ๋ฒ๋ ๊ฑด๋๋ฐ์ด์ง๋ฉฐ, ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฉ๋ชจ๋ฆฌ ๋์ ์์ด ํจ์จ์ ์ผ๋ก ๊ณ์ ์คํ๋ฉ๋๋ค. ์ฐ๋ฆฌ๋ ์ต์ ๋ฒ์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ์ฃผ์ฒด๋ก๋ถํฐ ์ฑ๊ณต์ ์ผ๋ก ๋ถ๋ฆฌํ์ต๋๋ค.
`WeakRefObserver` ํจํด์ ์ฌ์ฉํด์ผ ํ ๋ (๊ทธ๋ฆฌ๊ณ ํผํด์ผ ํ ๋)
์ด ํจํด์ ๊ฐ๋ ฅํ์ง๋ง ๋ง๋ณํต์น์ฝ์ ์๋๋๋ค. ๋ณต์ก์ฑ์ ๋์ ํ๊ณ ๋น๊ฒฐ์ ์ ๋์์ ์์กดํฉ๋๋ค. ์ธ์ ์ด ํจํด์ด ์ ํฉํ ๋๊ตฌ์ธ์ง ์๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
์ด์์ ์ธ ์ฌ์ฉ ์ฌ๋ก
- ์ฅ์๋ช ์ฃผ์ฒด์ ๋จ์๋ช ์ต์ ๋ฒ: ์ด๊ฒ์ด ์ ํ์ ์ธ ์ฌ์ฉ ์ฌ๋ก์ ๋๋ค. ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ์๋ช ์ฃผ๊ธฐ ๋์ ์กด์ฌํ๋ ์ ์ญ ์๋น์ค, ๋ฐ์ดํฐ ์ ์ฅ์ ๋๋ ์บ์(์ฃผ์ฒด)์, ์๋ง์ UI ์ปดํฌ๋ํธ, ์์ ์์ปค ๋๋ ํ๋ฌ๊ทธ์ธ(์ต์ ๋ฒ)์ด ๋น๋ฒํ๊ฒ ์์ฑ๋๊ณ ํ๊ดด๋๋ ๊ฒฝ์ฐ์ ๋๋ค.
- ์บ์ฑ ๋ฉ์ปค๋์ฆ: ๋ณต์กํ ๊ฐ์ฒด๋ฅผ ์ด๋ค ๊ณ์ฐ๋ ๊ฒฐ๊ณผ์ ๋งคํํ๋ ์บ์๋ฅผ ์์ํด ๋ณด์ธ์. ํค ๊ฐ์ฒด์ `WeakRef`๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ง์ฝ ์๋ ๊ฐ์ฒด๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋จธ์ง ๋ถ๋ถ์์ ๊ฐ๋น์ง ์ปฌ๋ ์ ๋๋ฉด, `FinalizationRegistry`๊ฐ ์บ์์ ํด๋น ํญ๋ชฉ์ ์๋์ผ๋ก ์ ๋ฆฌํ์ฌ ๋ฉ๋ชจ๋ฆฌ ํฝ์ฐฝ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
- ํ๋ฌ๊ทธ์ธ ๋ฐ ํ์ฅ ์ํคํ ์ฒ: ์๋ํํฐ ๋ชจ๋์ด ์ด๋ฒคํธ์ ๊ตฌ๋ ํ ์ ์๋๋ก ํ๋ ํต์ฌ ์์คํ ์ ๊ตฌ์ถํ๋ ๊ฒฝ์ฐ, `WeakRefObserver`๋ฅผ ์ฌ์ฉํ๋ฉด ๋ณต์๋ ฅ์ด ํ์ธต ๊ฐํ๋ฉ๋๋ค. ๊ตฌ๋ ์ทจ์๋ฅผ ์์ ์๋ชป ์์ฑ๋ ํ๋ฌ๊ทธ์ธ์ด ํต์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ์ผ์ผํค๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค.
- DOM ์์์ ๋ฐ์ดํฐ ๋งคํ: ์ ์ธ์ ํ๋ ์์ํฌ๊ฐ ์๋ ์๋๋ฆฌ์ค์์ DOM ์์์ ์ผ๋ถ ๋ฐ์ดํฐ๋ฅผ ์ฐ๊ฒฐํ๊ณ ์ถ์ ์ ์์ต๋๋ค. ๋ง์ฝ DOM ์์๋ฅผ ํค๋ก ํ๋ ๋งต์ ์ด๋ฅผ ์ ์ฅํ๋ฉด, ์์๊ฐ DOM์์ ์ ๊ฑฐ๋์์ง๋ง ๋งต์๋ ์ฌ์ ํ ๋จ์ ์์ ๊ฒฝ์ฐ ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ์ฌ๊ธฐ์๋ `WeakMap`์ด ๋ ๋์ ์ ํ์ด์ง๋ง ์์น์ ๋์ผํฉ๋๋ค: ๋ฐ์ดํฐ์ ์๋ช ์ฃผ๊ธฐ๋ ์์์ ์๋ช ์ฃผ๊ธฐ์ ๋ฌถ์ฌ์ผ ํ๋ฉฐ, ๊ทธ ๋ฐ๋๊ฐ ๋์ด์๋ ์ ๋ฉ๋๋ค.
ํด๋์ ์ต์ ๋ฒ๋ฅผ ๊ณ ์ํด์ผ ํ ๋
- ๋ฐ์ ํ๊ฒ ๊ฒฐํฉ๋ ์๋ช ์ฃผ๊ธฐ: ์ฃผ์ฒด์ ์ต์ ๋ฒ๊ฐ ํญ์ ํจ๊ป ๋๋ ๋์ผํ ๋ฒ์ ๋ด์์ ์์ฑ๋๊ณ ํ๊ดด๋๋ค๋ฉด, `WeakRef`์ ์ค๋ฒํค๋์ ๋ณต์ก์ฑ์ ๋ถํ์ํฉ๋๋ค. ๊ฐ๋จํ๊ณ ๋ช ์์ ์ธ `unsubscribe()` ํธ์ถ์ด ๋ ์ฝ๊ธฐ ์ฝ๊ณ ์์ธก ๊ฐ๋ฅํฉ๋๋ค.
- ์ฑ๋ฅ์ด ์ค์ํ ํซ ํจ์ค(Hot Path): `deref()` ๋ฉ์๋์๋ ์์ง๋ง 0์ด ์๋ ์ฑ๋ฅ ๋น์ฉ์ด ์์ต๋๋ค. ์ด๋น ์๋ฐฑ ๋ฒ์ฉ ์์ฒ ๊ฐ์ ์ต์ ๋ฒ์๊ฒ ์๋ฆผ์ ๋ณด๋ด๋ ๊ฒฝ์ฐ(์: ๊ฒ์ ๋ฃจํ ๋๋ ๊ณ ๋น๋ ๋ฐ์ดํฐ ์๊ฐํ), ์ง์ ์ฐธ์กฐ๋ฅผ ์ฌ์ฉํ๋ ํด๋์ ๊ตฌํ์ด ๋ ๋น ๋ฅผ ๊ฒ์ ๋๋ค.
- ๊ฐ๋จํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฐ ์คํฌ๋ฆฝํธ: ์ ํ๋ฆฌ์ผ์ด์ ์๋ช ์ด ์งง๊ณ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๊ฐ ์ค์ํ ๊ด์ฌ์ฌ๊ฐ ์๋ ์๊ท๋ชจ ์ ํ๋ฆฌ์ผ์ด์ ์ด๋ ์คํฌ๋ฆฝํธ์ ๊ฒฝ์ฐ, ํด๋์ ํจํด์ด ๊ตฌํํ๊ณ ์ดํดํ๊ธฐ ๋ ๊ฐ๋จํฉ๋๋ค. ํ์ํ์ง ์์ ๊ณณ์ ๋ณต์ก์ฑ์ ์ถ๊ฐํ์ง ๋ง์ธ์.
- ๊ฒฐ์ ๋ก ์ ์ ๋ฆฌ๊ฐ ํ์ํ ๋: ์ต์ ๋ฒ๊ฐ ๋ถ๋ฆฌ๋๋ ์ ํํ ์๊ฐ์ ์ด๋ค ์์ ์ ์ํํด์ผ ํ๋ ๊ฒฝ์ฐ(์: ์นด์ดํฐ ์ ๋ฐ์ดํธ, ํน์ ํ๋์จ์ด ๋ฆฌ์์ค ํด์ ), ๋ฐ๋์ ์๋ `unsubscribe()` ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค. `FinalizationRegistry`์ ๋น๊ฒฐ์ ์ ํน์ฑ์ ์์ธก ๊ฐ๋ฅํ๊ฒ ์คํ๋์ด์ผ ํ๋ ๋ก์ง์๋ ๋ถ์ ํฉํฉ๋๋ค.
์ํํธ์จ์ด ์ํคํ ์ฒ์ ๋ํ ๊ด๋ฒ์ํ ํจ์
JavaScript์ ๊ฐ์ ๊ณ ์์ค ์ธ์ด์ ์ฝํ ์ฐธ์กฐ๊ฐ ๋์ ๋ ๊ฒ์ ํ๋ซํผ์ ์ฑ์์ ์๋ฏธํฉ๋๋ค. ์ด๋ ๊ฐ๋ฐ์๋ค์ด ํนํ ์ฅ๊ธฐ ์คํ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํด ๋ ์ ๊ตํ๊ณ ํ๋ ฅ์ ์ธ ์์คํ ์ ๊ตฌ์ถํ ์ ์๊ฒ ํด์ค๋๋ค. ์ด ํจํด์ ์ํคํ ์ฒ์ ์ฌ๊ณ ์ ์ ํ์ ์ฅ๋ คํฉ๋๋ค:
- ์ง์ ํ ๋์ปคํ๋ง(๊ฒฐํฉ๋ ๋ฎ์ถ๊ธฐ): ์ด๋ ๋จ์ํ ์ธํฐํ์ด์ค๋ฅผ ๋์ด์๋ ์์ค์ ๋์ปคํ๋ง์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค. ์ด์ ์ฐ๋ฆฌ๋ ์ปดํฌ๋ํธ์ ์๋ช ์ฃผ๊ธฐ ์์ฒด๋ฅผ ๋ถ๋ฆฌํ ์ ์์ต๋๋ค. ์ฃผ์ฒด๋ ๋ ์ด์ ์ต์ ๋ฒ๊ฐ ์ธ์ ์์ฑ๋๊ฑฐ๋ ํ๊ดด๋๋์ง์ ๋ํด ์๋ฌด๊ฒ๋ ์ ํ์๊ฐ ์์ต๋๋ค.
- ์ค๊ณ์ ์ํ ๋ณต์๋ ฅ: ํ๋ก๊ทธ๋๋จธ์ ์ค์์ ๋ ๊ฐํ ์์คํ ์ ๊ตฌ์ถํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค. ์์ด๋ฒ๋ฆฐ `unsubscribe()` ํธ์ถ์ ์ถ์ ํ๊ธฐ ์ด๋ ค์ด ํํ ๋ฒ๊ทธ์ ๋๋ค. ์ด ํจํด์ ๊ทธ ์ ํ์ ์ค๋ฅ ์ ์ฒด๋ฅผ ์ํํฉ๋๋ค.
- ํ๋ ์์ํฌ ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ์์ ์ง์: ๋ค๋ฅธ ๊ฐ๋ฐ์๋ฅผ ์ํ ํ๋ ์์ํฌ, ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋๋ ํ๋ซํผ์ ๊ตฌ์ถํ๋ ์ฌ๋๋ค์๊ฒ ์ด๋ฌํ ๋๊ตฌ๋ ๋งค์ฐ ๊ท์คํฉ๋๋ค. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์๋น์์ ์ํ ์ค์ฉ์ ๋ ์ทจ์ฝํ ๊ฒฌ๊ณ ํ API๋ฅผ ์์ฑํ ์ ์๊ฒ ํ์ฌ, ์ ๋ฐ์ ์ผ๋ก ๋ ์์ ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ์ด์ด์ง๋๋ค.
๊ฒฐ๋ก : ํ๋ JavaScript ๊ฐ๋ฐ์๋ฅผ ์ํ ๊ฐ๋ ฅํ ๋๊ตฌ
ํด๋์ ์ต์ ๋ฒ ํจํด์ ์ํํธ์จ์ด ๋์์ธ์ ๊ธฐ๋ณธ ๊ตฌ์ฑ ์์์ด์ง๋ง, ๊ฐํ ์ฐธ์กฐ์ ๋ํ ์์กด์ฑ์ ์ค๋ซ๋์ JavaScript ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ฏธ๋ฌํ๊ณ ์ข์ ๊ฐ์ ์ฃผ๋ ๋ฉ๋ชจ๋ฆฌ ๋์์ ์์ธ์ด์์ต๋๋ค. ES2021์ `WeakRef`์ `FinalizationRegistry`๊ฐ ๋ฑ์ฅํ๋ฉด์, ์ฐ๋ฆฌ๋ ์ด์ ์ด ํ๊ณ๋ฅผ ๊ทน๋ณตํ ์ ์๋ ๋๊ตฌ๋ฅผ ๊ฐ๊ฒ ๋์์ต๋๋ค.
์ฐ๋ฆฌ๋ ๋จ์์๋ ์ฐธ์กฐ๋ผ๋ ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ ๋ฅผ ์ดํดํ๋ ๊ฒ์์๋ถํฐ ์์ํ์ฌ, ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ธ์ํ๋ ์์ ํ `WeakRefSubject`๋ฅผ ์ฒ์๋ถํฐ ๊ตฌ์ถํ๋ ์ฌ์ ์ ๊ฑฐ์ณค์ต๋๋ค. ์ฐ๋ฆฌ๋ `WeakRef`๊ฐ '๊ด์ฐฐ'๋๊ณ ์์ ๋์๋ ๊ฐ์ฒด๊ฐ ๊ฐ๋น์ง ์ปฌ๋ ์ ๋ ์ ์๊ฒ ํ๋ ๋ฐฉ๋ฒ๊ณผ, `FinalizationRegistry`๊ฐ ์ฐ๋ฆฌ์ ์ต์ ๋ฒ ๋ชฉ๋ก์ ๊นจ๋ํ๊ฒ ์ ์งํ๊ธฐ ์ํ ์๋ํ๋ ์ ๋ฆฌ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํ๋ ๋ฐฉ๋ฒ์ ๋ณด์์ต๋๋ค.
๊ทธ๋ฌ๋ ํฐ ํ์๋ ํฐ ์ฑ ์์ด ๋ฐ๋ฆ ๋๋ค. ์ด๊ฒ๋ค์ ๋น๊ฒฐ์ ์ ํน์ฑ์ผ๋ก ์ธํด ์ ์คํ ๊ณ ๋ ค๊ฐ ํ์ํ ๊ณ ๊ธ ๊ธฐ๋ฅ์ ๋๋ค. ์ข์ ์ ํ๋ฆฌ์ผ์ด์ ์ค๊ณ์ ๋ถ์ง๋ฐํ ์๋ช ์ฃผ๊ธฐ ๊ด๋ฆฌ๋ฅผ ๋์ฒดํ๋ ๊ฒ์ด ์๋๋๋ค. ํ์ง๋ง ์ฅ์๋ช ์๋น์ค์ ๋จ๋ช ์ปดํฌ๋ํธ ๊ฐ์ ํต์ ๊ด๋ฆฌ์ ๊ฐ์ ์ฌ๋ฐ๋ฅธ ๋ฌธ์ ์ ์ ์ฉ๋ ๋, WeakRef ์ต์ ๋ฒ ํจํด์ ๋งค์ฐ ๊ฐ๋ ฅํ ๊ธฐ์ ์ ๋๋ค. ์ด๋ฅผ ๋ง์คํฐํจ์ผ๋ก์จ, ์ฌ๋ฌ๋ถ์ ํ๋์ ์ด๊ณ ๋์ ์ธ ์น์ ์๊ตฌ๋ฅผ ์ถฉ์กฑ์ํฌ ์ค๋น๊ฐ ๋ ๋ ๊ฒฌ๊ณ ํ๊ณ ํจ์จ์ ์ด๋ฉฐ ํ์ฅ ๊ฐ๋ฅํ JavaScript ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ฑํ ์ ์์ต๋๋ค.